#pragma once

#include "Log.h"
#include "Error.h"
#include "Socket.h"
#include <iostream>
#include <cstdlib>
#include <functional>
#include <cstring>
#include <string>
#include <cerrno>
#include <sys/epoll.h>
#include <unistd.h>

namespace epoll_server {
    class EpollServer {
    public:
        constexpr static int epollSize = 32; // epoll_create的参数，现已废弃，随便一个大于0的值就行
        constexpr static uint16_t defaultPort = 18989; // 服务器的默认端口
        constexpr static int defaultFd = -1; // 服务器创建出的fd的默认值
        constexpr static int defaultReceiveEventSize = 32; // _receive_events数组的默认大小
        constexpr static int receiveBufferSize = 1024; // read/recv缓冲区大小

    private:
        using func_t = std::function<std::string (const std::string&)>;

    private:
        uint16_t _port; // 服务器绑定的端口
        int _listen_sockfd; // 服务器的监听套接字
        func_t _handle_method; // 服务器对请求的处理方法
        int _epoll_fd; // epoll模型的句柄，本质上是一个fd(Linux万物皆文件)
        int _receive_events_size; // _receive_events数组的大小
        struct epoll_event* _receive_events; // 存放已经就绪的输入事件的数组，输入事件由就绪队列(按照就绪的先后顺序)拷贝得到

    public:
        EpollServer(const func_t& handle_method, const uint16_t& port)
            : _port(port)
            , _listen_sockfd(defaultFd)
            , _handle_method(handle_method)
            , _epoll_fd(defaultFd)
            , _receive_events_size(defaultReceiveEventSize)
            , _receive_events(new struct epoll_event[_receive_events_size])
        {
            std::memset(_receive_events, 0, sizeof(struct epoll_event) * defaultReceiveEventSize);
        }

        ~EpollServer() {
            if (_listen_sockfd != defaultFd) {
                close(_listen_sockfd);
                _listen_sockfd = defaultFd;
            }

            if (_epoll_fd != defaultFd) {
                close(_epoll_fd);
                _epoll_fd = defaultFd;
            }

            if (_receive_events != nullptr) {
                delete[] _receive_events;
                _receive_events = nullptr;
            }
        }

    public:
        void initServer() {
            //task 创建listen套接字并完成绑定和监听
            _listen_sockfd = Socket::getSocket();
            if (_listen_sockfd < 0) {
                logMessage(FATAL, "create listen_socket err!");
                exit(SOCKET_ERR);
            }
            Socket::bindSocket(_listen_sockfd, _port);
            Socket::listenSocket(_listen_sockfd);
            logMessage(NORMAL, "listen_socket %d init success!", _listen_sockfd);

            //task 创建epoll模型
            _epoll_fd = epoll_create(epollSize);
            if (_epoll_fd < 0) {
                logMessage(FATAL, "create epoll err!");
                exit(EPOLL_CREATE_ERR);
            }
            logMessage(NORMAL, "epoll %d create success!", _epoll_fd);

            //task 将listen套接字放进epoll中托管
            struct epoll_event ev;
            ev.events = EPOLLIN; // 托管输入事件
            ev.data.fd = _listen_sockfd; // 用于区分从就绪队列读取上来的事件来自哪一个sockfd
            epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, _listen_sockfd, &ev);

            logMessage(NORMAL, "init server success!");
        }

        void run() {
            int timeout = -1; // 阻塞式
            for (;;) {
                int n = epoll_wait(_epoll_fd, _receive_events, _receive_events_size, timeout);

                if (n < 0) {
                    logMessage(ERROR, "epoll wait err, code: %d, description: %s", errno, std::strerror(errno));

                }
                else if (n == 0) {
                    logMessage(NORMAL, "epoll wait time out...");

                }
                else if (n > 0) {
                    logMessage(NORMAL, "receive request success, start to handle request");

                    handleRequest(n);

                    logMessage(NORMAL, "request handle end");
                }
            }
        }

    private:
        /**
         * 处理请求
         * 
         * @param ready_events_num 已经就绪的事件个数
        */
        void handleRequest(const int& ready_events_num) {
            logMessage(DEBUG, "in handleRequest");
            for (int i = 0; i < ready_events_num; ++i) {
                uint32_t events = _receive_events[i].events;
                int sockfd = _receive_events[i].data.fd;

                if (sockfd == _listen_sockfd && (events & EPOLLIN)) { // listen套接字的读取事件
                    //task 处理accept
                    std::string client_ip;
                    uint16_t client_port;
                    int new_sockfd = Socket::acceptSocket(_listen_sockfd, &client_ip, &client_port);
                    if (new_sockfd < 0) {
                        logMessage(ERROR, "accept new connect err!");
                        continue;
                    }
                    logMessage(NORMAL, "accept a new sockfd %d", new_sockfd);

                    //task 将新获取的连接放进epoll中托管
                    //* 在获取新连接后不能直接read/recv，要是对方没发送数据过来，服务器就会阻塞在这里
                    struct epoll_event ev;
                    ev.events = EPOLLIN;
                    ev.data.fd = new_sockfd;
                    epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, new_sockfd, &ev); 
                }
                else if (events & EPOLLIN) { // 普通套接字的读取事件
                    char buffer[receiveBufferSize] = {};
                    ssize_t n = recv(sockfd, buffer, receiveBufferSize - 1, 0); // 因为epoll帮我们等待了，所以这里不会阻塞
                    if (n > 0) { // 成功读取到数据
                        //task 处理请求
                        buffer[n - 1] = '\0'; // 把'\n‘去除
                        std::string response = _handle_method(std::string(buffer));
                        logMessage(NORMAL, "handle request success, response: %s", response.c_str());

                        //task 把应答发送给客户端
                        send(sockfd, response.c_str(), response.size(), 0);
                        logMessage(NORMAL, "send response to client success!");
                    }
                    else if (n == 0) { // 客户端关闭
                        //* 需要先将sockfd从epoll中移除，再关闭sockfd
                        //* 因为epoll会对进行操作的fd检测有效性，如果先关sockfd再移除的话，可能会报错

                        // 因为epoll_ctl实质上是对epoll模型中的红黑树进行增删改，所以删除只需要key值不需要value值
                        epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, sockfd, nullptr);
                        close(sockfd);
                        logMessage(NORMAL, "client sockfd %d close", sockfd);
                    }
                    else { // n < 0
                        epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, sockfd, nullptr);
                        close(sockfd);
                        logMessage(ERROR, "handleRequest err! code: %d, description: %s", errno, strerror(errno));
                    }
                }
                else {
                    //todo
                }
            }
            logMessage(DEBUG, "out handleRequest");
        }

    }; //@end class EpollServer
} //@end namespace epoll_server